﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerMoveMent : MonoBehaviour
{

    private Rigidbody2D rb;
    private BoxCollider2D boxColl;

    [Header("移动参数")]
    public float speed = 8f;
    public float crouchSpeedDivisor = 3f;

    [Header("跳跃参数")]
    public float jumpForce = 6.3f;
    public float jumpHoldForce = 1.9f;
    public float jumpHoldDuration = 0.1f;
    public float crouchjumpBoost = 2.5f;
    public float hangingJumpForce = 15f;
    float jumpTime;

    [Header("状态")]
    float xVelocity;//X轴力的方向
    [SerializeField]
    bool isCrouch, isOnGround, isJump, isHeadBlocked, isHanging;
    [Header("环境监测")]
    public LayerMask groundLayer;
    public float footOffset = 0.4f;
    public float headClearance = 0.5f;
    public float groundDistance = 0.2f;
    float playerHeight;
    public float eyeHeight = 1.5f;
    public float grabDistance = 0.4f;
    public float reachOffset = 0.7f;

    //按键设置
    bool jumpPressed;
    bool jumpHeld;
    bool crouchHeld;
    bool crouchPressed;

    //碰撞体尺寸
    Vector2 collStandUpSize, collStandUpOffset;
    Vector2 collCrouchSize, collCrouchOffset;


    // Start is called before the first frame update
    void Start()
    {
        rb = GetComponent<Rigidbody2D>();
        boxColl = GetComponent<BoxCollider2D>();

        playerHeight = boxColl.size.y;

        collStandUpSize = boxColl.size;
        collStandUpOffset = boxColl.offset;
        collCrouchSize = new Vector2(boxColl.size.x, boxColl.size.y / 2);
        collCrouchOffset = new Vector2(boxColl.offset.x, boxColl.offset.y / 2);
    }

    // Update is called once per frame
    void Update()
    {
        jumpPressed = Input.GetButtonDown("Jump");
        jumpHeld = Input.GetButton("Jump");
        crouchHeld = Input.GetButton("Crouch");
        crouchPressed = Input.GetButtonDown("Crouch");
        MidAirMoveMent();
    }

    void FixedUpdate()
    {
        PhysicsCheck();
        GroundMoveMent();

    }

    //物理检测
    void PhysicsCheck()
    {
        // Vector2 pos = transform.position;
        // Vector2 lOffset = new Vector2(-footOffset, 0f);
        // RaycastHit2D leftCheck = Physics2D.Raycast(pos + lOffset, Vector2.down, groundDistance, groundLayer);
        // Debug.DrawRay(pos + lOffset, Vector2.down, Color.red, 0.2f);
        //左右脚射线
        RaycastHit2D leftCheck = Raycast(new Vector2(-footOffset, 0f), Vector2.down, groundDistance, groundLayer);
        RaycastHit2D rightCheck = Raycast(new Vector2(footOffset, 0f), Vector2.down, groundDistance, groundLayer);
        //头部射线
        RaycastHit2D headCheck = Raycast(new Vector2(0f, boxColl.size.y), Vector2.up, headClearance, groundLayer);
        isOnGround = leftCheck;
        isHeadBlocked = headCheck;

        float direction = transform.localScale.x;
        Vector2 grabDir = new Vector2(direction, 0f);
        RaycastHit2D blockedCheck = Raycast(new Vector2(footOffset * direction, playerHeight), grabDir, grabDistance, groundLayer);
        RaycastHit2D wallCheck = Raycast(new Vector2(footOffset * direction, eyeHeight), grabDir, grabDistance, groundLayer);
        RaycastHit2D ledgeCheck = Raycast(new Vector2(reachOffset * direction, playerHeight), Vector2.down, grabDistance, groundLayer);

        if (!isOnGround && rb.velocity.y < 0f && ledgeCheck && wallCheck && !blockedCheck)
        {
            Vector3 pos = transform.position;
            pos.x += (wallCheck.distance - 0.05f) * direction;
            pos.y -= ledgeCheck.distance;
            transform.position = pos;
            rb.bodyType = RigidbodyType2D.Static;
            isHanging = true;
        }

    }

    void GroundMoveMent()
    {
        if (isHanging) return;

        if (crouchHeld && !isCrouch && isOnGround)
        {
            Crouch();
        }
        else if ((!crouchHeld || !isOnGround) && isCrouch && !isHeadBlocked)
        {
            StandUp();
        }

        xVelocity = Input.GetAxis("Horizontal");
        if (isCrouch)
        {
            xVelocity /= crouchSpeedDivisor;
        }

        rb.velocity = new Vector2(xVelocity * speed, rb.velocity.y);
        FlipDirection();
    }

    void MidAirMoveMent()
    {

        if (isHanging)
        {

            if (jumpPressed)
            {
                rb.bodyType = RigidbodyType2D.Dynamic;
                isHanging = false;
                rb.velocity = new Vector2(rb.velocity.x, hangingJumpForce);
            }
            if (crouchPressed)
            {
                rb.bodyType = RigidbodyType2D.Dynamic;
                isHanging = false;
            }
        }

        if (jumpPressed && isOnGround && !isJump)
        {

            if (isCrouch && !isHeadBlocked)
            {
                StandUp();
                rb.AddForce(new Vector2(0f, crouchjumpBoost), ForceMode2D.Impulse);
            }

            isOnGround = false;
            isJump = true;
            jumpTime = Time.time + jumpHoldDuration;
            rb.AddForce(new Vector2(0f, jumpForce), ForceMode2D.Impulse);
        }
        else if (isJump)
        {
            if (jumpHeld)
            {
                rb.AddForce(new Vector2(0f, jumpHoldForce), ForceMode2D.Impulse);
            }
            if (jumpTime < Time.time)
            {
                isJump = false;
            }
        }
    }

    void FlipDirection()
    {
        if (xVelocity < 0)
            transform.localScale = new Vector2(-1, 1);
        if (xVelocity > 0)
            transform.localScale = new Vector2(1, 1);
    }

    void Crouch()
    {
        isCrouch = true;
        boxColl.size = collCrouchSize;
        boxColl.offset = collCrouchOffset;
    }

    void StandUp()
    {
        isCrouch = false;
        boxColl.size = collStandUpSize;
        boxColl.offset = collStandUpOffset;
    }

    RaycastHit2D Raycast(Vector2 offset, Vector2 rayDirection, float length, LayerMask layer)
    {
        Vector2 pos = transform.position;
        RaycastHit2D hit = Physics2D.Raycast(pos + offset, rayDirection, length, layer);
        Color color = hit ? Color.red : Color.green;
        Debug.DrawRay(pos + offset, rayDirection * length, color);
        return hit;
    }
}
